package impl

import (
	"context"
	"fmt"

	"gitee.com/lishixi/gops/vblog/apps/token"
	"gitee.com/lishixi/gops/vblog/apps/user"
	"github.com/infraboard/mcube/v2/ioc"
	"github.com/infraboard/mcube/v2/ioc/config/datasource"
	"github.com/infraboard/mcube/v2/ioc/config/log"
)

var _ token.Service = (*TokenUserServiceImpl)(nil)

func init() {
	ioc.Controller().Registry(&TokenUserServiceImpl{})
}

// 需要自己通过 ioc 获取依赖
type TokenUserServiceImpl struct {
	ioc.ObjectImpl
	user user.AdminService

	DefaultExpiredTTL int `json:"default_expired_ttl" toml:"default_expired_ttl" env:"DEFAULT_EXPIRED_TTL"`
}

func (*TokenUserServiceImpl) Name() string {
	return token.AppName
}

func (i *TokenUserServiceImpl) Init() error {
	i.user = user.GetService()
	log.L().Info().Msgf("DefaultExpiredTTL: %d", i.DefaultExpiredTTL)
	return nil
}

// IssueToken implements token.UserService.
func (t *TokenUserServiceImpl) IssueToken(ctx context.Context, in *token.IssueTokenRequest) (*token.Token, error) {
	if err := in.Validate(); err != nil {
		return nil, err
	}
	// 验证用户
	user, err := t.user.DescribeUser(ctx, &user.DescribeUserStatusRequest{
		DescribeBy: user.DESCRIBE_BY_USERNAME,
		Value:      in.UserName,
	})
	if err != nil {
		return nil, err
	}
	// 验证密码
	if err := user.CheckPassword(in.Password); err != nil {
		return nil, err
	}
	// 颁发 token
	token := token.NewToken(fmt.Sprintf("%d", user.Id)).SetRefUserName(in.UserName)

	//
	if in.RememberMe {
		token.AccessTokenexpireAt = token.RefreshTokenexpireAt
	}
	// 存储
	if err := datasource.DBFromCtx(ctx).Create(token).Error; err != nil {
		return nil, err
	}

	return token, nil
}

// RevolkToken implements token.UserService.
func (t *TokenUserServiceImpl) RevolkToken(context.Context, *token.RevolkTokenRequest) (*token.Token, error) {
	panic("unimplemented")
}

// ValidateToken implements token.Service.
func (t *TokenUserServiceImpl) ValidateToken(ctx context.Context, in *token.ValidateTokenRequest) (*token.Token, error) {
	// 校验 token
	tk := &token.Token{}
	if err := datasource.DBFromCtx(ctx).Where("access_token = ?", in.AccessToken).Take(tk).Error; err != nil {
		return nil, err
	}
	// 判断 token 是否过期
	if err := tk.IsAccessTokenExpired(); err != nil {
		return nil, err
	}
	// 补充用户信息
	user, err := t.user.DescribeUser(ctx, &user.DescribeUserStatusRequest{
		DescribeBy: user.DESCRIBE_BY_ID,
		Value:      tk.RefUserId,
	})
	if err != nil {
		return nil, err
	}
	tk.RefUserName = user.UserName

	return tk, nil
}
